home *** CD-ROM | disk | FTP | other *** search
/ Aminet 50 / Aminet 50 (2002)(GTI - Schatztruhe)[!][Aug 2002].iso / Aminet / text / tex / dvipdfm.lha / dvipdfm / pdfspecial.c < prev    next >
C/C++ Source or Header  |  2000-10-20  |  50KB  |  1,855 lines

  1. /*  $Header$
  2.  
  3.     This is dvipdfm, a DVI to PDF translator.
  4.     Copyright (C) 1998, 1999 by Mark A. Wicks
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.     
  20.     The author may be contacted via the e-mail address
  21.  
  22.     mwicks@kettering.edu
  23. */
  24.  
  25.     
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <ctype.h>
  29. #include <math.h>
  30. #include <string.h>
  31. #include "system.h"
  32. #include "mem.h"
  33. #include "mfileio.h"
  34. #include "numbers.h"
  35. #include "dvi.h"
  36. #include "pdflimits.h"
  37. #include "pdfspecial.h"
  38. #include "pdfobj.h"
  39. #include "pdfdoc.h"
  40. #include "pdfdev.h"
  41. #include "pdfparse.h"
  42. #include "jpeg.h"
  43. #include "epdf.h"
  44. #include "mpost.h"
  45. #include "psimage.h"
  46.  
  47. #include "config.h"
  48.  
  49. #ifdef HAVE_LIBPNG
  50. #include <png.h>
  51. #include "pngimage.h"
  52. #endif /* HAVE_LIBPNG */
  53.  
  54. #define verbose 0
  55. #define debug 0
  56.  
  57. static void add_reference (char *name, pdf_obj *object, char *res_name);
  58. static void release_reference (char *name);
  59. static pdf_obj *lookup_reference(char *name);
  60. static char *lookup_ref_res_name (char *name);
  61. static pdf_obj *lookup_object(char *name);
  62. static void do_content (char **start, char *end, double x_user, double
  63.             y_user);
  64. static void do_image(char **start, char *end, double x_user, double y_user);
  65. static pdf_obj *jpeg_start_image (FILE *file);
  66. static void finish_image (pdf_obj *image_res, struct xform_info *p,
  67.               char *res_name);
  68. static void do_bxobj (char **start, char *end,
  69.               double x_user, double y_user);
  70. static void do_exobj (void);
  71. static void do_uxobj (char **start, char *end, double x_user, double
  72.               y_user);
  73.  
  74. static char ignore_colors = 0;
  75. static double annot_grow = 0.0;
  76.  
  77. void pdf_special_set_grow (double g)
  78. {
  79.   annot_grow = g;
  80. }
  81. double pdf_special_tell_grow (void)
  82. {
  83.   return annot_grow;
  84. }
  85.  
  86. void pdf_special_ignore_colors(void)
  87. {
  88.   ignore_colors = 1;
  89. }
  90.  
  91. static void do_bop(char **start, char *end)
  92. {
  93. #ifdef MEM_DEBUG
  94.   MEM_START
  95. #endif
  96.   if (*start < end)
  97.     pdf_doc_bop (*start, end - *start);
  98.   *start = end;
  99. #ifdef MEM_DEBUG
  100.   MEM_END
  101. #endif
  102.   return;
  103. }
  104.  
  105. static void do_eop(char **start, char *end)
  106. {
  107. #ifdef MEM_DEBUG
  108.   MEM_START
  109. #endif
  110.   if (*start < end)
  111.     pdf_doc_eop (*start, end - *start);
  112.   *start = end;
  113. #ifdef MEM_DEBUG
  114.   MEM_END
  115. #endif
  116. }
  117.  
  118. pdf_obj *get_reference(char **start, char *end)
  119. {
  120.   char *name, *save = *start;
  121.   pdf_obj *result = NULL;
  122. #ifdef MEM_DEBUG
  123. MEM_START
  124. #endif
  125.   skip_white (start, end);
  126.   if ((name = parse_pdf_reference(start, end)) != NULL) {
  127.     if ((result = lookup_reference (name)) == NULL) {
  128.       fprintf (stderr, "\nNamed reference (@%s) doesn't exist.\n", name);
  129.       *start = save;
  130.       dump(*start, end);
  131.     }
  132.     RELEASE (name);
  133.   }
  134. #ifdef MEM_DEBUG
  135. MEM_END
  136. #endif
  137.   return result;
  138. }
  139.  
  140. pdf_obj *get_reference_lvalue(char **start, char *end)
  141. {
  142.   char *name, *save = *start;
  143.   pdf_obj *result = NULL;
  144. #ifdef MEM_DEBUG
  145. MEM_START
  146. #endif
  147.   skip_white (start, end);
  148.   if ((name = parse_pdf_reference(start, end)) != NULL) {
  149.     result = lookup_object (name);
  150.     if (result == NULL) {
  151.       fprintf (stderr, "\nNamed object (@%s) doesn't exist.\n", name);
  152.       *start = save;
  153.       dump(*start, end);
  154.     }
  155.     RELEASE (name);
  156.   }
  157. #ifdef MEM_DEBUG
  158. MEM_END
  159. #endif
  160.   return result;
  161. }
  162.  
  163. static void do_put(char **start, char *end)
  164. {
  165.   pdf_obj *result = NULL, *data = NULL;
  166.   char *save = *start;
  167.   skip_white(start, end);
  168.   if ((result = get_reference_lvalue(start, end)) != NULL) {
  169.     skip_white (start, end);
  170.     save = *start;
  171.     switch (result -> type) {
  172.     case PDF_DICT:
  173.       if ((data = parse_pdf_dict (start, end)) != NULL &&
  174.       data -> type == PDF_DICT) {
  175.     pdf_merge_dict (result, data);
  176.       } else{
  177.     fprintf (stderr, "\nSpecial put:  Expecting a dictionary\n");
  178.     *start = save;
  179.     dump(*start, end);
  180.       }
  181.       if (data != NULL)
  182.     pdf_release_obj (data);
  183.       break;
  184.     case PDF_ARRAY:
  185.       while (*start < end && 
  186.          (data = parse_pdf_object (start, end)) != NULL) {
  187.     pdf_add_array (result, data);
  188.     skip_white(start, end);
  189.       }
  190.       if (*start < end) {
  191.     fprintf (stderr, "\nSpecial: put: invalid object.  Rest of line ignored.\n");
  192.     *start = save;
  193.     dump(*start, end);
  194.       }
  195.       break;
  196.     default:
  197.       fprintf (stderr, "\nSpecial put:  Invalid destination object type\n");
  198.       break;
  199.     }
  200.   }
  201.   else {
  202.     fprintf (stderr, "\nSpecial put:  Nonexistent object reference\n");
  203.   }
  204.   return;
  205. }
  206.  
  207. /* The following must be consecutive and
  208.    starting at 0.  Order must match
  209.    dimensions array below */
  210.  
  211. #define WIDTH 0
  212. #define HEIGHT 1
  213. #define DEPTH 2
  214. #define SCALE 3
  215. #define XSCALE 4
  216. #define YSCALE 5
  217. #define ROTATE 6
  218. #define BBOX 7
  219.  
  220. struct {
  221.   char *s;
  222.   int key;
  223.   int hasunits;
  224. } dimensions[] = {
  225.   {"width", WIDTH, 1},
  226.   {"height", HEIGHT, 1},
  227.   {"depth", DEPTH, 1},
  228.   {"scale", SCALE, 0},
  229.   {"xscale", XSCALE, 0},
  230.   {"yscale", YSCALE, 0},
  231.   {"rotate", ROTATE, 0},
  232.   {"bbox", BBOX, 0}
  233. };
  234.  
  235. struct xform_info *new_xform_info (void)
  236. {
  237.   struct xform_info *result;
  238.   result = NEW (1, struct xform_info);
  239.   result -> width = 0.0;
  240.   result -> height = 0.0;
  241.   result -> depth = 0.0;
  242.   result -> scale = 0.0;
  243.   result -> xscale = 0.0;
  244.   result -> yscale = 0.0;
  245.   result -> rotate = 0.0;
  246.   result -> user_bbox = 0;
  247.   result -> clip = 0;
  248.  /* These next two must be initialized be cause
  249.     they represent the reference point even
  250.     if the user doesn't specify one.  We must
  251.     have a reference point */
  252.   result -> u_llx = 0.0;
  253.   result -> u_lly = 0.0;
  254.   return result;
  255. }
  256.  
  257. void release_xform_info (struct xform_info *p)
  258. {
  259.   RELEASE (p);
  260.   return;
  261. }
  262.  
  263. int validate_image_xform_info (struct xform_info *p)
  264. {
  265.   int result = 1;
  266.   if (p->width != 0.0)
  267.     if (p->scale !=0.0 || p->xscale != 0.0) {
  268.       fprintf (stderr, "\nCan't supply both width and scale\n");
  269.       result = 0;
  270.     }
  271.   if (p->height != 0.0) 
  272.     if (p->scale !=0.0 || p->yscale != 0.0) {
  273.       fprintf (stderr, "\nCan't supply both height and scale\n");
  274.       result = 0;
  275.     }
  276.   if (p->scale != 0.0)
  277.     if (p->xscale != 0.0 || p->yscale != 0.0) {
  278.       fprintf (stderr, "\nCan't supply overall scale along with axis scales");
  279.       result = 0;
  280.     }
  281.   return result;
  282. }
  283.  
  284. static int parse_one_dim_word (char **start, char *end)
  285. {
  286.   int i;
  287.   char *dimension_string;
  288.   char *save = *start;
  289.   int result = -1;
  290.   skip_white(start, end);
  291.   if ((dimension_string = parse_ident(start, end)) != NULL) {
  292.     for (i=0; i<sizeof(dimensions)/sizeof(dimensions[0]); i++) {
  293.       if (!strcmp (dimensions[i].s, dimension_string))
  294.     break;
  295.     }
  296.     if (i != sizeof(dimensions)/sizeof(dimensions[0])) {
  297.       result =  dimensions[i].key;
  298.     } else {
  299.       fprintf (stderr, "\n%s: Invalid keyword\n", dimension_string);
  300.     }
  301.     RELEASE (dimension_string);
  302.   }
  303.   if (result < 0) {
  304.     *start = save;
  305.     fprintf (stderr, "\nExpecting a keyword here, e.g., height, width, etc.\n");
  306.     dump(*start, end);
  307.   }
  308.   return result;
  309. }
  310.  
  311. struct {
  312.   char *s;
  313.   double units;
  314.   int is_true_unit;
  315. } units[] = {
  316.   {"pt", (72.0/72.27), 0},
  317.   {"in", (72.0), 0},
  318.   {"cm", (72.0/2.54), 0},
  319.   {"mm", (72.0/25.4), 0},
  320.   {"truept", (72.0/72.27), 1},
  321.   {"truein", (72.0), 1},
  322.   {"truecm", (72.0/2.54), 1},
  323.   {"truemm", (72.0/25.4), 1}
  324. };
  325.   
  326. double parse_one_unit (char **start, char *end)
  327. {
  328.   int i;
  329.   char *unit_string = NULL, *save = *start;
  330.   double result = -1.0;
  331.   int errors = 0;
  332.   skip_white(start, end);
  333.   if ((unit_string = parse_c_ident(start, end)) != NULL) {
  334.     for (i=0; i<sizeof(units)/sizeof(units[0]); i++) {
  335.       if (!strcmp (units[i].s, unit_string))
  336.     break;
  337.     }
  338.     if (i == sizeof(units)/sizeof(units[0])) {
  339.       fprintf (stderr,
  340.            "\n%s: Invalid unit of measurement (should be in, cm, pt, etc.)\n", unit_string);
  341.       errors = 1;
  342.     }
  343.     if (i != sizeof(units)/sizeof(units[0]) && !units[i].is_true_unit)
  344.       result = units[i].units;
  345.     /* If these are "true" units, we must pre-shrink since the entire
  346.        document is magnified */
  347.     if (i != sizeof(units)/sizeof(units[0]) && units[i].is_true_unit)
  348.       result = units[i].units/dvi_tell_mag();
  349.     RELEASE (unit_string);
  350.   }
  351.   if (!unit_string || errors) {
  352.     fprintf (stderr, "\nExpecting a unit here (e.g., in, cm, pt)\n");
  353.     *start = save; 
  354.     dump(*start, end);
  355.   }
  356.   return result;
  357. }
  358.  
  359. static int parse_dimension (char **start, char *end,
  360.                 struct xform_info *p)
  361. {
  362.   char *number_string = NULL;
  363.   char *save = NULL;
  364.   double units = -1.0;
  365.   int key, error = 0;
  366.   skip_white(start, end);
  367.   while (*start < end && isalpha (**start)) {
  368.     save = *start;
  369.     if ((key = parse_one_dim_word(start, end)) >= 0) {
  370.       skip_white(start, end);
  371.     } else {
  372.       fprintf (stderr,
  373.            "\nExpecting a dimension/transformation keyword (e.g., width, height) here:\n");
  374.       error = 1;
  375.       break;
  376.     }
  377.     if (key != BBOX) { /* BBOX is handled somewhat differently than
  378.               all the others  */
  379.       number_string = parse_number(start, end);
  380.       if (key >= 0 && number_string == NULL) {
  381.     fprintf (stderr, "Expecting a number following dimension/transformation keyword\n");
  382.     error = 1;
  383.     break;
  384.       }
  385.       /* If we got a key and a number, see if we need a dimension also */
  386.       if (key >= 0 && number_string != NULL && dimensions[key].hasunits) {
  387.     skip_white(start, end);
  388.     if ((units = parse_one_unit(start, end)) < 0.0) {
  389.       fprintf (stderr, "\nExpecting a dimension unit\n");
  390.       error = 1;
  391.     }
  392.       }
  393.       if (!error && key >= 0 && number_string != NULL) {
  394.     switch (key) {
  395.     case WIDTH:
  396.       if (p->width != 0.0)
  397.         fprintf (stderr, "\nDuplicate width specified: %s\n", number_string);
  398.       p->width = atof (number_string)*units;
  399.       break;
  400.     case HEIGHT:
  401.       if (p->height != 0.0)
  402.         fprintf (stderr, "\nDuplicate height specified: %s\n", number_string);
  403.       p->height = atof (number_string)*units;
  404.       break;
  405.     case DEPTH:
  406.       if (p->depth != 0.0)
  407.         fprintf (stderr, "\nDuplicate depth specified: %s\n", number_string);
  408.       p->depth = atof (number_string)*units;
  409.       break;
  410.     case SCALE:
  411.       if (p->scale != 0.0)
  412.         fprintf (stderr, "\nDuplicate depth specified: %s\n", number_string);
  413.       p->scale = atof (number_string);
  414.       break;
  415.     case XSCALE:
  416.       if (p->xscale != 0.0)
  417.         fprintf (stderr, "\nDuplicate xscale specified: %s\n", number_string);
  418.       p->xscale = atof (number_string);
  419.       break;
  420.     case YSCALE:
  421.       if (p->yscale != 0.0)
  422.         fprintf (stderr, "\nDuplicate yscale specified: %s\n", number_string);
  423.       p->yscale = atof (number_string);
  424.       break;
  425.     case ROTATE:
  426.       if (p->rotate != 0)
  427.         fprintf (stderr, "\nDuplicate rotation specified: %s\n", number_string);
  428.       p->rotate = atof (number_string) * M_PI / 180.0;
  429.       break;
  430.     default:
  431.       ERROR ("parse_dimension: Invalid key");
  432.     }
  433.     if (number_string != NULL) {
  434.       RELEASE (number_string);
  435.       number_string = NULL;
  436.     }
  437.       }
  438.     } else { /* BBox case handled here */
  439.       char *llx = NULL, *lly = NULL, *urx = NULL, *ury = NULL;
  440.       if ((llx = parse_number (start, end)) &&
  441.       (lly = parse_number (start, end)) &&
  442.       (urx = parse_number (start, end)) &&
  443.       (ury = parse_number (start, end))) {
  444.     p->u_llx = atof (llx);
  445.     p->u_lly = atof (lly);
  446.     p->u_urx = atof (urx);
  447.     p->u_ury = atof (ury);
  448.     p->user_bbox = 1; /* Flag to indicate that user specified a bbox */
  449.       } else {
  450.     fprintf (stderr, "\nExpecting four numbers following \"bbox\" specification.\n");
  451.     error = 1; /* Flag error, but don't break until we get a
  452.               chance to free structures */
  453.       }
  454.       if (llx) RELEASE (llx);
  455.       if (lly) RELEASE (lly);
  456.       if (urx) RELEASE (urx);
  457.       if (ury) RELEASE (ury);
  458.       if (error) break;
  459.     }
  460.     skip_white(start, end);
  461.   }
  462.   if (error && save)
  463.     dump (save, end);
  464.   return !error;
  465. }
  466.  
  467. static void do_pagesize(char **start, char *end)
  468. {
  469.   struct xform_info *p;
  470.   int error = 0;
  471.   p = new_xform_info();
  472.   skip_white(start, end);
  473.   if (parse_dimension(start, end, p)) {
  474.     if (p->scale != 0.0 || p->xscale != 0.0 || p->yscale != 0.0) {
  475.       fprintf (stderr, "\nScale meaningless for pagesize\n");
  476.       error = 1;
  477.     }
  478.     if (p->width == 0.0 || p->depth + p->height == 0.0) {
  479.       fprintf (stderr, "\nPage cannot have a zero dimension\n");
  480.       error = 1;
  481.     }
  482.   } else {
  483.     fprintf (stderr, "\nSpecial: pagesize: Failed to find a valid set of dimensions\n");
  484.     dump (*start, end);
  485.     error = 1;
  486.   }
  487.   if (!error)
  488.     /* Since these are physical dimensions, they need to be scaled by
  489.        mag.  "Virtual" dimensions are scaled by a transformation
  490.        matrix.  Physical dimensions (e.g, page size and annotations)
  491.        cannot */
  492.     dev_set_page_size (dvi_tell_mag()*p->width, dvi_tell_mag()*(p->depth + p->height));
  493.   release_xform_info (p);
  494.   return;
  495. }
  496.  
  497.  
  498. static void do_ann(char **start, char *end)
  499. {
  500.   pdf_obj *result = NULL, *rectangle = NULL;
  501.   char *name = NULL;
  502.   int error = 0;
  503.   struct xform_info *p;
  504. #ifdef MEM_DEBUG
  505. MEM_START
  506. #endif
  507.   p = new_xform_info();
  508.   skip_white(start, end);
  509.   name = parse_opt_ident(start, end);
  510.   skip_white(start, end);
  511.   if (parse_dimension(start, end, p)) {
  512.     if (p->scale != 0.0 || p->xscale != 0.0 || p->yscale != 0.0) {
  513.       fprintf (stderr, "\nScale meaningless for annotations\n");
  514.       error = 1;
  515.     }
  516.     if (p->width == 0.0 || p->depth + p->height == 0.0) {
  517.       fprintf (stderr, "Special ann: Rectangle has a zero dimension\n");
  518.       fprintf (stderr, "Special ann: Annotations require both horizontal and vertical dimensions\n");
  519.       error = 1;
  520.     }
  521.   }
  522.   if (!error && (result = parse_pdf_dict(start, end)) != NULL) {
  523.     rectangle = pdf_new_array();
  524.     pdf_add_array (rectangle, pdf_new_number(ROUND(dev_phys_x()-annot_grow,0.01)));
  525.     pdf_add_array (rectangle, pdf_new_number(ROUND(dev_phys_y()-dvi_tell_mag()*p->depth-annot_grow,0.01)));
  526.     pdf_add_array (rectangle, pdf_new_number(ROUND(dev_phys_x()+dvi_tell_mag()*p->width+annot_grow,0.01)));
  527.     pdf_add_array (rectangle, pdf_new_number(ROUND(dev_phys_y()+dvi_tell_mag()*p->height+annot_grow,0.01)));
  528.     pdf_add_dict (result, pdf_new_name ("Rect"),
  529.           rectangle);
  530.     pdf_doc_add_to_page_annots (pdf_ref_obj (result));
  531.     /* If this object has a named reference, we file it away for
  532.        later.  Otherwise we release it */
  533.     if (name != NULL) {
  534.       add_reference (name, result, NULL);
  535.       /* An annotation is treated differently from a cos object.
  536.      cos objects are kept open for the user.  We forcibly
  537.          "close" the annotation by calling release_reference */
  538.       release_reference (name);
  539.     } else
  540.       pdf_release_obj (result);
  541.   } else {
  542.     fprintf (stderr, "Ignoring annotation with invalid dictionary\n");
  543.     error = 1;
  544.   }
  545.   release_xform_info (p);
  546.   if (name)
  547.     RELEASE (name);
  548. #ifdef MEM_DEBUG
  549. MEM_END
  550. #endif
  551.   return;
  552. }
  553.  
  554. pdf_obj *pending_annot_dict = NULL;
  555. static void do_bann(char **start, char *end)
  556. {
  557.   int error = 0;
  558. #ifdef MEM_DEBUG
  559. MEM_START
  560. #endif
  561.   if (!pending_annot_dict) {
  562.     skip_white(start, end);
  563.     if ((pending_annot_dict = parse_pdf_dict(start, end)) != NULL) {
  564.       pdf_doc_begin_annot (pending_annot_dict);
  565.       /* If this object has a named reference, we file it away for
  566.      later.  Otherwise we release it */
  567.     } else {
  568.       fprintf (stderr, "Ignoring annotation with invalid dictionary\n");
  569.       error = 1;
  570.     }
  571.   } else {
  572.     fprintf (stderr, "\nCan't begin an annotation when one is pending.\n");
  573.   }
  574. #ifdef MEM_DEBUG
  575. MEM_END
  576. #endif
  577.   return;
  578. }
  579.  
  580. static void do_eann(char **start, char *end)
  581. {
  582. #ifdef MEM_DEBUG
  583. MEM_START
  584. #endif
  585.   if (pending_annot_dict) {
  586.     pdf_doc_end_annot ();
  587.     pdf_release_obj (pending_annot_dict);
  588.     pending_annot_dict = NULL;
  589.   } else {
  590.     fprintf (stderr, "\nTried to end an annotation without starting one!\n");
  591.   }
  592. #ifdef MEM_DEBUG
  593. MEM_END
  594. #endif
  595.   return;
  596. }
  597.  
  598. static void do_bgcolor(char **start, char *end)
  599. {
  600.   char *save = *start;
  601.   pdf_obj *color;
  602.   int error = 0;
  603.   skip_white(start, end);
  604.   if ((color = parse_pdf_object(start, end)) != NULL &&
  605.       (color -> type == PDF_ARRAY ||
  606.        color -> type == PDF_NUMBER )) {
  607.     switch (color -> type) {
  608.       int i;
  609.     case PDF_ARRAY:
  610.       for (i=0; i<5; i++) {
  611.     if (pdf_get_array (color, i) == NULL ||
  612.         pdf_get_array (color, i) -> type != PDF_NUMBER)
  613.       break;
  614.       }
  615.       switch (i) {
  616.       case 3:
  617.     dev_bg_rgb_color (pdf_number_value (pdf_get_array (color,0)),
  618.               pdf_number_value (pdf_get_array (color,1)),
  619.               pdf_number_value (pdf_get_array (color,2)));
  620.     break;
  621.       case 4:
  622.     dev_bg_cmyk_color (pdf_number_value (pdf_get_array (color,0)),
  623.                pdf_number_value (pdf_get_array (color,1)),
  624.                pdf_number_value (pdf_get_array (color,2)),
  625.                pdf_number_value (pdf_get_array (color,3)));
  626.     break;
  627.       default:
  628.     fprintf (stderr, "\nSpecial: begincolor: Expecting either RGB or CMYK color array\n");
  629.     error = 1;
  630.       }
  631.       break;
  632.     case PDF_NUMBER:
  633.       dev_bg_gray (pdf_number_value (color));
  634.     }
  635.   } else {
  636.     fprintf (stderr, "\nSpecial: background color: Expecting color specified by an array or number\n");
  637.     error = 1;
  638.   }
  639.   if (error) {
  640.     *start = save;
  641.     dump (*start, end);
  642.   }
  643.   if (color)
  644.     pdf_release_obj (color);
  645.   return;
  646. }
  647.  
  648. static void do_bcolor(char **start, char *end)
  649. {
  650.   char *save = *start;
  651.   pdf_obj *color;
  652.   int error = 0;
  653. #ifdef MEM_DEBUG
  654.   MEM_START
  655. #endif /* MEM_DEBUG */
  656.   skip_white(start, end);
  657.   if ((color = parse_pdf_object(start, end)) != NULL &&
  658.       (color -> type == PDF_ARRAY ||
  659.        color -> type == PDF_NUMBER )) {
  660.     switch (color -> type) {
  661.       int i;
  662.     case PDF_ARRAY:
  663.       for (i=0; i<5; i++) {
  664.     if (pdf_get_array (color, i) == NULL ||
  665.         pdf_get_array (color, i) -> type != PDF_NUMBER)
  666.       break;
  667.       }
  668.       switch (i) {
  669.       case 3:
  670.     dev_begin_rgb_color (pdf_number_value (pdf_get_array (color,0)),
  671.                  pdf_number_value (pdf_get_array (color,1)),
  672.                  pdf_number_value (pdf_get_array (color,2)));
  673.     break;
  674.       case 4:
  675.     dev_begin_cmyk_color (pdf_number_value (pdf_get_array (color,0)),
  676.                   pdf_number_value (pdf_get_array (color,1)),
  677.                   pdf_number_value (pdf_get_array (color,2)),
  678.                   pdf_number_value (pdf_get_array (color,3)));
  679.     break;
  680.       default:
  681.     fprintf (stderr, "\nSpecial: begincolor: Expecting either RGB or CMYK color array\n");
  682.     error = 1;
  683.       }
  684.       break;
  685.     case PDF_NUMBER:
  686.       dev_begin_gray (pdf_number_value (color));
  687.     }
  688.   } else {
  689.     fprintf (stderr, "\nSpecial: Begincolor: Expecting color specified by an array or number\n");
  690.     error = 1;
  691.   }
  692.   if (error) {
  693.     *start = save;
  694.     dump (*start, end);
  695.   }
  696.   if (color)
  697.     pdf_release_obj (color);
  698. #ifdef MEM_DEBUG
  699.   MEM_END
  700. #endif /* MEM_DEBUG */
  701.   return;
  702. }
  703.  
  704. static void do_scolor(char **start, char *end)
  705. {
  706.   char *save = *start;
  707.   pdf_obj *color;
  708.   int error = 0;
  709. #ifdef MEM_DEBUG
  710.   MEM_START
  711. #endif /* MEM_DEBUG */
  712.   skip_white(start, end);
  713.   if ((color = parse_pdf_object(start, end)) != NULL &&
  714.       (color -> type == PDF_ARRAY ||
  715.        color -> type == PDF_NUMBER )) {
  716.     switch (color -> type) {
  717.       int i;
  718.     case PDF_ARRAY:
  719.       for (i=0; i<5; i++) {
  720.     if (pdf_get_array (color, i) == NULL ||
  721.         pdf_get_array (color, i) -> type != PDF_NUMBER)
  722.       break;
  723.       }
  724.       switch (i) {
  725.       case 3:
  726.     dev_set_def_rgb_color (pdf_number_value (pdf_get_array (color,0)),
  727.                    pdf_number_value (pdf_get_array (color,1)),
  728.                    pdf_number_value (pdf_get_array (color,2)));
  729.     break;
  730.       case 4:
  731.     dev_set_def_cmyk_color (pdf_number_value (pdf_get_array (color,0)),
  732.                 pdf_number_value (pdf_get_array (color,1)),
  733.                 pdf_number_value (pdf_get_array (color,2)),
  734.                 pdf_number_value (pdf_get_array (color,3)));
  735.     break;
  736.       default:
  737.     fprintf (stderr, "\nSpecial: begincolor: Expecting either RGB or CMYK color array\n");
  738.     error = 1;
  739.       }
  740.       break;
  741.     case PDF_NUMBER:
  742.       dev_set_def_gray (pdf_number_value (color));
  743.     }
  744.   } else {
  745.     fprintf (stderr, "\nSpecial: Begincolor: Expecting color specified by an array or number\n");
  746.     error = 1;
  747.   }
  748.   if (error) {
  749.     *start = save;
  750.     dump (*start, end);
  751.   }
  752.   if (color)
  753.     pdf_release_obj (color);
  754. #ifdef MEM_DEBUG
  755.   MEM_END
  756. #endif /* MEM_DEBUG */
  757.   return;
  758. }
  759.  
  760. static void do_bgray(char **start, char *end)
  761. {
  762.   char *number_string;
  763.   skip_white(start, end);
  764.   if ((number_string = parse_number (start, end)) != NULL) {
  765.     dev_begin_gray (atof (number_string));
  766.     RELEASE (number_string);
  767.   } else {
  768.     fprintf (stderr, "\nSpecial: begingray: Expecting a numerical grayscale specification\n");
  769.   }
  770.   return;
  771. }
  772.  
  773. static void do_ecolor(void)
  774. {
  775.   dev_end_color();
  776. }
  777.  
  778. static void do_egray(void)
  779. {
  780.   dev_end_color();
  781. }
  782.  
  783. static void do_bxform (char **start, char *end, double x_user, double y_user)
  784. {
  785.   int error = 0;
  786.   char *save = *start;
  787.   struct xform_info *p;
  788.   p = new_xform_info ();
  789. #ifdef MEM_DEBUG
  790.   MEM_START
  791. #endif
  792.   skip_white (start, end);
  793.   if (parse_dimension (start, end, p)) {
  794.     if (!validate_image_xform_info (p)) {
  795.       fprintf (stderr, "\nSpecified dimensions are inconsistent\n");
  796.       fprintf (stderr, "\nSpecial will be ignored\n");
  797.       error = 1;
  798.     }
  799.     if (p -> width != 0.0 || p -> height != 0.0 || p -> depth != 0.0) {
  800.       fprintf (stderr, "Special: bt: width, height, and depth are meaningless\n");
  801.       fprintf (stderr, "Special: bt: These will be ignored\n");
  802.       /* This isn't really a fatal error */
  803.     }
  804.     if (p -> scale != 0.0) {
  805.       p->xscale = p->scale;
  806.       p->yscale = p->scale;
  807.     }
  808.     if (p -> xscale == 0.0)
  809.       p->xscale = 1.0;
  810.     if (p -> yscale == 0.0)
  811.       p->yscale = 1.0;
  812.   } else {
  813.     fprintf (stderr, "\nError in transformation parameters\n");
  814.     error = 1;
  815.   }
  816.   if (!error) {
  817.     dev_begin_xform (p->xscale, p->yscale, p->rotate, x_user, y_user);
  818.   } else {
  819.     *start = save;
  820.     dump (*start, end);
  821.   }
  822.   release_xform_info (p);
  823. #ifdef MEM_DEBUG
  824. MEM_END
  825. #endif
  826.   return;
  827. }
  828.  
  829. static void do_exform(void)
  830. {
  831. #ifdef MEM_DEBUG
  832. MEM_START
  833. #endif
  834.   dev_end_xform();
  835. #ifdef MEM_DEBUG
  836. MEM_END
  837. #endif
  838. }
  839.  
  840. static void do_outline(char **start, char *end)
  841. {
  842.   pdf_obj *level = NULL, *result;
  843.   int error = 0;
  844.   char *save; 
  845.   static int lowest_level = 255;
  846.   skip_white(start, end);
  847.   save = *start; 
  848.   if ((level = parse_pdf_object(start, end)) != NULL &&
  849.       level -> type == PDF_NUMBER) {
  850.     /* Make sure we know where the starting level is */
  851.     if ( (int) pdf_number_value (level) < lowest_level)
  852.       lowest_level = (int) pdf_number_value (level);
  853.  
  854.     if ((result = parse_pdf_dict(start, end)) != NULL) {
  855.       pdf_doc_change_outline_depth
  856.     ((int)pdf_number_value(level)-lowest_level+1);
  857.       pdf_doc_add_outline (result);
  858.     } else {
  859.       fprintf (stderr, "\nIgnoring invalid dictionary\n");
  860.       error = 1;
  861.     }
  862.   } else {
  863.     fprintf (stderr, "\nSpecial: outline: Expecting number for object level.\n");
  864.     *start = save;
  865.     error = 1;
  866.   }
  867.   if (error)
  868.     dump (*start, end);
  869.   if (level)
  870.     pdf_release_obj (level);
  871.   return;
  872. }
  873.  
  874. static void do_article(char **start, char *end)
  875. {
  876.   char *name = NULL, *save = *start;
  877.   int error = 0;
  878.   pdf_obj *info_dict = NULL;
  879.   skip_white (start, end);
  880.   if (*((*start)++) != '@' || (name = parse_ident(start, end)) == NULL) {
  881.     fprintf (stderr, "Article name expected.\n");
  882.     *start = save;
  883.     dump (*start, end);
  884.     error = 1;
  885.   }
  886.   if (!error && (info_dict = parse_pdf_dict(start, end)) == NULL) {
  887.     fprintf (stderr, "Ignoring invalid dictionary\n");
  888.     error = 1;
  889.   }
  890.   if (!error) {
  891.     pdf_doc_start_article (name, pdf_link_obj(info_dict));
  892.     add_reference (name, info_dict, NULL);
  893.   }
  894.   if (name)
  895.     RELEASE (name);
  896.   return;
  897. }
  898.  
  899. static void do_bead(char **start, char *end)
  900. {
  901.   pdf_obj *bead_dict, *rectangle, *article, *info_dict = NULL;
  902.   int error = 0;
  903.   char *name = NULL, *save = *start;
  904.   struct xform_info *p;
  905.   p = new_xform_info();
  906.   skip_white(start, end);
  907.   if (*((*start)++) != '@' || (name = parse_ident(start, end)) == NULL) {
  908.     fprintf (stderr, "Article reference expected.\nWhich article does this go with?\n");
  909.     error = 1;
  910.   }
  911.   /* If okay so far, try to get a bounding box */
  912.   if (!error) {
  913.     skip_white(start, end);
  914.     if (!parse_dimension(start, end, p)) {
  915.       fprintf (stderr, "\nSpecial: thread: Error in bounding box specification for this bead\n");
  916.       error = 1;
  917.     }
  918.     if (p->scale != 0.0 || p->xscale != 0.0 || p->yscale != 0.0) {
  919.       fprintf (stderr, "\nScale meaningless for annotations\n");
  920.       error = 1;
  921.     }
  922.     if (p->width == 0.0 || p->depth + p->height == 0.0) {
  923.       fprintf (stderr, "\nSpecial thread: Rectangle has a zero dimension\n");
  924.       error = 1;
  925.     }
  926.   }
  927.   if (!error) {
  928.     skip_white (start, end);
  929.     if (**start == '<') {
  930.       if ((info_dict = parse_pdf_dict (start, end)) ==
  931.     NULL) {
  932.     fprintf (stderr, "\nSpecial: thread: Error in dictionary\n");
  933.     error = 1;
  934.       }
  935.     } else
  936.       info_dict = pdf_new_dict();
  937.   }
  938.   if (!error && name && info_dict) {
  939.     /* Does this article exist yet */
  940.     if ((article = lookup_object (name)) == NULL) {
  941.       pdf_doc_start_article (name, pdf_link_obj (info_dict));
  942.       add_reference (name, info_dict, NULL);
  943.     } else {
  944.       pdf_merge_dict (article, info_dict);
  945.       pdf_release_obj (info_dict);
  946.       info_dict = NULL;
  947.     }
  948.     bead_dict = pdf_new_dict ();
  949.     rectangle = pdf_new_array();
  950.     pdf_add_array (rectangle, pdf_new_number(ROUND(dev_phys_x(),0.01)));
  951.     pdf_add_array (rectangle, pdf_new_number(ROUND(dev_phys_y()-p->depth,0.01)));
  952.     pdf_add_array (rectangle, pdf_new_number(ROUND(dev_phys_x()+p->width,0.01)));
  953.     pdf_add_array (rectangle, pdf_new_number(ROUND(dev_phys_y()+p->height,0.01)));
  954.     pdf_add_dict (bead_dict, pdf_new_name ("R"),
  955.           rectangle);
  956.     pdf_add_dict (bead_dict, pdf_new_name ("P"),
  957.           pdf_doc_this_page_ref());
  958.     pdf_doc_add_bead (name, bead_dict);
  959.   }
  960.   release_xform_info(p);
  961.   if (name != NULL) {
  962.     RELEASE (name);
  963.   }
  964.   if (error) {
  965.     *start = save;
  966.     dump (*start, end);
  967.   }
  968.   return;
  969. }
  970.  
  971. pdf_obj *embed_image (char *filename, struct xform_info *p,
  972.              double x_user, double y_user, char *objname) 
  973. {
  974.   pdf_obj *result = NULL;
  975.   char *kpse_file_name;
  976.   FILE *image_file;
  977.   static char res_name[16];
  978.   static long next_image = 1;
  979.   sprintf (res_name, "Im%ld", next_image);
  980.   if ((kpse_file_name = kpse_find_pict (filename)) &&
  981.       (image_file = MFOPEN (kpse_file_name, FOPEN_RBIN_MODE))) {
  982.     fprintf (stderr, "(%s", kpse_file_name);
  983.     if (check_for_jpeg(image_file)) {
  984.       result = jpeg_start_image(image_file);
  985.       if (result)
  986.     finish_image (result, p, res_name);
  987.     }
  988. #ifdef HAVE_LIBPNG
  989.     else if (check_for_png(image_file)) {
  990.       fprintf (stderr, "<PNG>");
  991.       result = start_png_image (image_file, NULL);
  992.       if (result)
  993.     finish_image (result, p, res_name);
  994.     }
  995. #endif
  996.     else if (check_for_pdf (image_file)) {
  997.       fprintf (stderr, "<PDF>");
  998.       result = pdf_include_page (image_file, p, res_name);
  999.     }
  1000.     else if (check_for_mp (image_file)) {
  1001.       fprintf (stderr, "<MPOST>");
  1002.       result = mp_include (image_file, p, res_name, x_user, y_user);
  1003.     }
  1004.     /* Make sure we check for PS *after* checking for MP since
  1005.        MP is a special case of PS */
  1006.     else if (check_for_ps (image_file)) {
  1007.       fprintf (stderr, "<PS>");
  1008.       result = ps_include (kpse_file_name, p,
  1009.                res_name, x_user, y_user);
  1010.     }
  1011.     else{
  1012.       fprintf (stderr, "<?>");
  1013.       result = ps_include (kpse_file_name, p,
  1014.                res_name, x_user, y_user);
  1015.     }
  1016.     MFCLOSE (image_file);
  1017.     fprintf (stderr, ")");
  1018.   } else {
  1019.       fprintf (stderr, "\nError locating or opening file (%s)\n", filename);
  1020.   }
  1021.   if (result) { /* Put reference to object on page */
  1022.     next_image += 1;
  1023.     pdf_doc_add_to_page_xobjects (res_name, pdf_ref_obj(result));
  1024.     pdf_doc_add_to_page (" q", 2);
  1025.     add_xform_matrix (x_user, y_user,
  1026.               p->xscale/pdf_dev_scale(), p->yscale/pdf_dev_scale(), p->rotate);
  1027.     if (p->depth != 0.0)
  1028.       add_xform_matrix (0.0, -p->depth, 1.0, 1.0, 0.0);
  1029.     sprintf (work_buffer, " /%s Do Q", res_name);
  1030.     pdf_doc_add_to_page (work_buffer, strlen(work_buffer));
  1031.   } else {
  1032.     fprintf (stderr, "\npdf: image inclusion failed for (%s).\n", filename);
  1033.   }
  1034.   if (objname != NULL && result != NULL) {
  1035.     add_reference (objname, pdf_link_obj (result), res_name);
  1036.     /* Read the explanation for the next line in do_ann() */
  1037.     release_reference (objname);
  1038.   }
  1039.   return result;
  1040. }
  1041.  
  1042. static void do_image (char **start, char *end, double x_user, double y_user)
  1043. {
  1044.   char *filename = NULL, *objname = NULL, *save;
  1045.   pdf_obj *filestring = NULL, *result = NULL;
  1046.   int error = 0;
  1047.   struct xform_info *p;
  1048. #ifdef MEM_DEBUG
  1049. MEM_START
  1050. #endif
  1051.   skip_white(start, end);
  1052.   objname = parse_opt_ident(start, end);
  1053.   p = new_xform_info();
  1054.   skip_white(start, end);
  1055.   save = *start;
  1056.   if (!parse_dimension(start, end, p)) {
  1057.     fprintf (stderr, "\nError in dimensions of encapsulated image\n");
  1058.     error = 1;
  1059.   }
  1060.   skip_white(start, end);
  1061.   if (!error && (filestring = parse_pdf_string(start, end)) == NULL) {
  1062.     fprintf (stderr, "\nMissing filename\n");
  1063.     error = 1;
  1064.   }
  1065.   if (!error) {
  1066.     filename = pdf_string_value(filestring);
  1067.   }
  1068.   if (!error && !validate_image_xform_info (p)) {
  1069.     fprintf (stderr, "\nSpecified dimensions are inconsistent\n");
  1070.     dump (save, end);
  1071.     error = 1;
  1072.   }
  1073.   if (!error)
  1074.     result = embed_image (filename, p, x_user, y_user, objname);
  1075.   else
  1076.     dump (save, end);
  1077.   if (p)
  1078.     release_xform_info (p);
  1079.   if (objname)
  1080.     RELEASE (objname);
  1081.   if (filestring)
  1082.     pdf_release_obj (filestring);
  1083.   if (error || !result)
  1084.     fprintf (stderr, "Image special ignored.\n");
  1085.   if (result)
  1086.     pdf_release_obj (result);
  1087.   return;
  1088. #ifdef MEM_DEBUG
  1089. MEM_END
  1090. #endif
  1091. }
  1092.  
  1093. static void do_dest(char **start, char *end)
  1094. {
  1095.   pdf_obj *name;
  1096.   pdf_obj *array;
  1097. #ifdef MEM_DEBUG
  1098. MEM_START
  1099. #endif
  1100.   skip_white(start, end);
  1101.   if ((name = parse_pdf_string(start, end)) == NULL) {
  1102.     fprintf (stderr, "\nPDF string expected and not found.\n");
  1103.     fprintf (stderr, "Special dest: ignored\n");
  1104.     dump(*start, end);
  1105.     return;
  1106.   }
  1107.   if ((array = parse_pdf_array(start, end)) == NULL) {
  1108.     pdf_release_obj (name);
  1109.     return;
  1110.   }
  1111.   pdf_doc_add_dest (pdf_obj_string_value(name),
  1112.             pdf_obj_string_length(name),
  1113.             pdf_ref_obj (array));
  1114.   pdf_release_obj (name);
  1115.   pdf_release_obj (array);
  1116. #ifdef MEM_DEBUG
  1117. MEM_END
  1118. #endif
  1119. }
  1120.  
  1121. static void do_docinfo(char **start, char *end)
  1122. {
  1123.   pdf_obj *result;
  1124.   if ((result = parse_pdf_dict(start, end)) != NULL) {
  1125.     pdf_doc_merge_with_docinfo (result);
  1126.   } else {
  1127.     fprintf (stderr, "\nSpecial: docinfo: Dictionary expected and not found\n");
  1128.     dump (*start, end);
  1129.   }
  1130.   pdf_release_obj (result);
  1131.   return;
  1132. }
  1133.  
  1134. static void do_docview(char **start, char *end)
  1135. {
  1136.   pdf_obj *result;
  1137.   if ((result = parse_pdf_dict(start, end)) != NULL) {
  1138.     pdf_doc_merge_with_catalog (result);
  1139.   } else {
  1140.     fprintf (stderr, "\nSpecial: docview: Dictionary expected and not found\n");
  1141.     dump (*start, end);
  1142.   }
  1143.   pdf_release_obj (result);
  1144.   return;
  1145. }
  1146.  
  1147.  
  1148. static void do_close(char **start, char *end)
  1149. {
  1150.   char *name;
  1151.   skip_white(start, end);
  1152.   if ((name = parse_pdf_reference(start, end)) != NULL) {
  1153.     release_reference (name);
  1154.     RELEASE (name);
  1155.   }
  1156.   return;
  1157. }
  1158.  
  1159. static void do_obj(char **start, char *end)
  1160. {
  1161.   pdf_obj *result;
  1162.   char *name;
  1163.   skip_white(start, end);
  1164.   name = parse_opt_ident(start, end);
  1165.   if ((result = parse_pdf_object(start, end)) == NULL) {
  1166.     fprintf (stderr, "Special object: Ignored.\n");
  1167.     return;
  1168.   };
  1169.   if (name != NULL) {
  1170.     add_reference (name, result, NULL);
  1171.     RELEASE (name);
  1172.   }
  1173.   return;
  1174. }
  1175.  
  1176. static void do_content(char **start, char *end, double x_user, double y_user)
  1177. {
  1178.   int len;
  1179.   if (*start < end) {
  1180.     len = sprintf (work_buffer, " q 1 0 0 1 %.2f %.2f cm ", x_user, y_user);
  1181.     pdf_doc_add_to_page (work_buffer, len);
  1182.     pdf_doc_add_to_page (*start, end-*start);
  1183.     pdf_doc_add_to_page (" Q", 2);
  1184.   }
  1185.   *start = end;
  1186.   return;
  1187. }
  1188.  
  1189.  
  1190. static int is_pdf_special (char **start, char *end)
  1191. {
  1192.   skip_white(start, end);
  1193.   if (end-*start >= strlen ("pdf:") &&
  1194.       !strncmp (*start, "pdf:", strlen("pdf:"))) {
  1195.     *start += strlen("pdf:");
  1196.     return 1;
  1197.   }
  1198.   return 0;
  1199. }
  1200.  
  1201. #define ANN 1
  1202. #define OUTLINE 2
  1203. #define ARTICLE 3
  1204. #define DEST 4
  1205. #define DOCINFO 7
  1206. #define DOCVIEW 8
  1207. #define OBJ 9
  1208. #define CONTENT 10
  1209. #define PUT 11
  1210. #define CLOSE 12
  1211. #define BOP 13
  1212. #define EOP 14
  1213. #define BEAD 15
  1214. #define EPDF 16
  1215. #define IMAGE 17
  1216. #define BCOLOR 18
  1217. #define ECOLOR 19
  1218. #define BGRAY  20
  1219. #define EGRAY  21
  1220. #define BGCOLOR 22
  1221. #define BXFORM 23
  1222. #define EXFORM 24
  1223. #define PAGE_SIZE 25
  1224. #define BXOBJ 26
  1225. #define EXOBJ 27
  1226. #define UXOBJ 28
  1227. #define SCOLOR 29
  1228. #define BANN   30
  1229. #define EANN   31
  1230. #define LINK_ANNOT 32
  1231. #define NOLINK_ANNOT 33
  1232.  
  1233. struct pdfmark
  1234. {
  1235.   char *string;
  1236.   int value;
  1237. } pdfmarks[] = {
  1238.   {"ann", ANN},
  1239.   {"annot", ANN},
  1240.   {"annotate", ANN},
  1241.   {"annotation", ANN},
  1242.   {"out", OUTLINE},
  1243.   {"outline", OUTLINE},
  1244.   {"art", ARTICLE},
  1245.   {"article", ARTICLE},
  1246.   {"bead", BEAD},
  1247.   {"thread", BEAD},
  1248.   {"dest", DEST},
  1249.   {"docinfo", DOCINFO},
  1250.   {"docview", DOCVIEW},
  1251.   {"obj", OBJ},
  1252.   {"object", OBJ},
  1253.   {"content", CONTENT},
  1254.   {"put", PUT},
  1255.   {"close", CLOSE},
  1256.   {"bop", BOP},
  1257.   {"eop", EOP},
  1258.   {"epdf", EPDF},
  1259.   {"image", IMAGE},
  1260.   {"img", IMAGE},
  1261.   {"bc", BCOLOR},
  1262.   {"bcolor", BCOLOR},
  1263.   {"begincolor", BCOLOR},
  1264.   {"link", LINK_ANNOT},
  1265.   {"nolink", NOLINK_ANNOT},
  1266.   {"sc", SCOLOR},
  1267.   {"scolor", SCOLOR},
  1268.   {"setcolor", SCOLOR},
  1269.   {"ec", ECOLOR},
  1270.   {"ecolor", ECOLOR},
  1271.   {"endcolor", ECOLOR},
  1272.   {"bg", BGRAY},
  1273.   {"bgray", BGRAY},
  1274.   {"begingray", BGRAY},
  1275.   {"eg", EGRAY},
  1276.   {"egray", EGRAY},
  1277.   {"endgray", EGRAY},
  1278.   {"bgcolor", BGCOLOR},
  1279.   {"bgc", BGCOLOR},
  1280.   {"bbc", BGCOLOR},
  1281.   {"bbg", BGCOLOR},
  1282.   {"pagesize", PAGE_SIZE},
  1283.   {"beginann", BANN},
  1284.   {"bann", BANN},
  1285.   {"bannot", BANN},
  1286.   {"eann", EANN},
  1287.   {"endann", EANN},
  1288.   {"eannot", EANN},
  1289.   {"begintransform", BXFORM},
  1290.   {"begintrans", BXFORM},
  1291.   {"btrans", BXFORM},
  1292.   {"bt", BXFORM},
  1293.   {"endtransform", EXFORM},
  1294.   {"endtrans", EXFORM},
  1295.   {"etrans", EXFORM},
  1296.   {"et", EXFORM},
  1297.   {"beginxobj", BXOBJ},
  1298.   {"bxobj", BXOBJ},
  1299.   {"endxobj", EXOBJ},
  1300.   {"exobj", EXOBJ},
  1301.   {"usexobj", UXOBJ},
  1302.   {"uxobj", UXOBJ}
  1303. };
  1304.  
  1305. static int parse_pdfmark (char **start, char *end)
  1306. {
  1307.   char *save;
  1308.   int i;
  1309.   if (verbose) {
  1310.     fprintf (stderr, "\nparse_pdfmark:");
  1311.     dump (*start, end);
  1312.   }
  1313.   skip_white(start, end);
  1314.   if (*start >= end) {
  1315.     fprintf (stderr, "Special ignored...no pdfmark found\n");
  1316.     return -1;
  1317.   }
  1318.   
  1319.   save = *start;
  1320.   while (*start < end && isalpha (**start))
  1321.     (*start)++;
  1322.   for (i=0; i<sizeof(pdfmarks)/sizeof(struct pdfmark); i++) {
  1323.     if (*start-save == strlen (pdfmarks[i].string) &&
  1324.     !strncmp (save, pdfmarks[i].string,
  1325.           strlen(pdfmarks[i].string)))
  1326.       return pdfmarks[i].value;
  1327.   }
  1328.   *start = save;
  1329.   fprintf (stderr, "\nExpecting pdfmark (and didn't find one)\n");
  1330.   dump(*start, end);
  1331.   return -1;
  1332. }
  1333.  
  1334. struct named_reference 
  1335. {
  1336.   char *name;
  1337.   char *res_name;
  1338.   pdf_obj *object_ref;
  1339.   pdf_obj *object;
  1340. } *named_references = NULL;
  1341. static unsigned long number_named_references = 0, max_named_objects = 0;
  1342.  
  1343. static void add_reference (char *name, pdf_obj *object, char *res_name)
  1344. {
  1345.   int i;
  1346.   if (number_named_references >= max_named_objects) {
  1347.     max_named_objects += NAMED_OBJ_ALLOC_SIZE;
  1348.     named_references = RENEW (named_references, max_named_objects,
  1349.                   struct named_reference);
  1350.   }
  1351.   for (i=0; i<number_named_references; i++) {
  1352.     if (!strcmp (named_references[i].name, name)) {
  1353.       break;
  1354.     }
  1355.   }
  1356.   if (i != number_named_references) {
  1357.     fprintf (stderr, "\nWarning: @%s: Duplicate named reference ignored\n", name);
  1358.   }
  1359.   named_references[number_named_references].name = NEW (strlen
  1360.                             (name)+1,
  1361.                             char);
  1362.   strcpy (named_references[number_named_references].name, name);
  1363.   if (res_name != NULL && strlen(res_name) != 0) {
  1364.     named_references[number_named_references].res_name=NEW(strlen(name)+1, char);
  1365.     strcpy (named_references[number_named_references].res_name,
  1366.         res_name);
  1367.   } else {
  1368.     named_references[number_named_references].res_name = NULL;
  1369.   }
  1370.   named_references[number_named_references].object_ref = pdf_ref_obj(object);
  1371.   named_references[number_named_references].object = object;
  1372.   number_named_references+=1;
  1373. }
  1374. /* The following routine returns copies, not the original object */
  1375. static pdf_obj *lookup_reference(char *name)
  1376. {
  1377.   int i;
  1378.   /* First check for builtins first */
  1379.   if (!strcmp (name, "ypos")) {
  1380.     return pdf_new_number(ROUND(dev_phys_y(),0.01));
  1381.   }
  1382.   if (!strcmp (name, "xpos")) {
  1383.     return pdf_new_number(ROUND(dev_phys_x(),0.01));
  1384.   }
  1385.   if (!strcmp (name, "thispage")) {
  1386.     return pdf_doc_this_page_ref();
  1387.   }
  1388.   if (!strcmp (name, "prevpage")) {
  1389.     return pdf_doc_prev_page_ref();
  1390.   }
  1391.   if (!strcmp (name, "nextpage")) {
  1392.     return pdf_doc_next_page_ref();
  1393.   }
  1394.   if (!strcmp (name, "pages")) {
  1395.     return pdf_ref_obj (pdf_doc_page_tree());
  1396.   }
  1397.   if (!strcmp (name, "names")) {
  1398.     return pdf_ref_obj (pdf_doc_names());
  1399.   }
  1400.   if (!strcmp (name, "resources")) {
  1401.     return pdf_ref_obj (pdf_doc_current_page_resources());
  1402.   }
  1403.   if (!strcmp (name, "catalog")) {
  1404.     return pdf_ref_obj (pdf_doc_catalog());
  1405.   }
  1406.  
  1407.   if (strlen (name) > 4 &&
  1408.       !strncmp (name, "page", 4) &&
  1409.       is_an_int (name+4)) {
  1410.     return pdf_doc_ref_page(atoi (name+4));
  1411.   }
  1412.   for (i=0; i<number_named_references; i++) {
  1413.     if (!strcmp (named_references[i].name, name)) {
  1414.       break;
  1415.     }
  1416.   }
  1417.   if (i == number_named_references)
  1418.     return NULL;
  1419.   return (pdf_link_obj (named_references[i].object_ref));
  1420. }
  1421.  
  1422. static pdf_obj *lookup_object(char *name)
  1423. {
  1424.   int i;
  1425.   if (!strcmp (name, "thispage")) {
  1426.     return pdf_doc_this_page();
  1427.   }
  1428.   if (!strcmp (name, "pages")) {
  1429.     return pdf_doc_page_tree();
  1430.   }
  1431.   if (!strcmp (name, "names")) {
  1432.     return pdf_doc_names();
  1433.   }
  1434.   if (!strcmp (name, "resources")) {
  1435.     return pdf_doc_current_page_resources();
  1436.   }
  1437.   if (!strcmp (name, "catalog")) {
  1438.     return pdf_doc_catalog();
  1439.   }
  1440.  
  1441.   for (i=0; i<number_named_references; i++) {
  1442.     if (!strcmp (named_references[i].name, name)) {
  1443.       break;
  1444.     }
  1445.   }
  1446.   if (i == number_named_references)
  1447.     return NULL;
  1448.   if (named_references[i].object == NULL)
  1449.     fprintf (stderr, "lookup_object: Referenced object not defined or already closed\n");
  1450.   return (named_references[i].object);
  1451. }
  1452.  
  1453. char *lookup_ref_res_name(char *name)
  1454. {
  1455.   int i;
  1456.   for (i=0; i<number_named_references; i++) {
  1457.   if (named_references[i].name != NULL)
  1458.     if (named_references[i].name != NULL &&
  1459.     !strcmp (named_references[i].name, name)) {
  1460.       break;
  1461.     }
  1462.   }
  1463.   if (i == number_named_references)
  1464.     return NULL;
  1465.   if (named_references[i].res_name == NULL)
  1466.     fprintf (stderr, "lookup_object: Referenced object not useable as a form!\n");
  1467.   return (named_references[i].res_name);
  1468. }
  1469.  
  1470. static void release_reference (char *name)
  1471. {
  1472.   int i;
  1473.   for (i=0; i<number_named_references; i++) {
  1474.     if (!strcmp (named_references[i].name, name)) {
  1475.       break;
  1476.     }
  1477.   }
  1478.   if (i == number_named_references) {
  1479.     fprintf (stderr, "\nrelease_reference: tried to release nonexistent reference\n");
  1480.     return;
  1481.   }
  1482.   if (named_references[i].object != NULL) {
  1483.     pdf_release_obj (named_references[i].object);
  1484.     named_references[i].object = NULL;
  1485.   }
  1486.   else
  1487.     fprintf (stderr, "\nrelease_reference: @%s: trying to close an object twice?\n", name);
  1488. }
  1489.  
  1490.  
  1491. void pdf_finish_specials (void)
  1492. {
  1493.   int i;
  1494.   /* Flush out any pending objects that weren't properly closeed.
  1495.      Threads never get closed.  Is this a bug? */
  1496.   for (i=0; i<number_named_references; i++) {
  1497.     pdf_release_obj (named_references[i].object_ref);
  1498.     if (named_references[i].object != NULL) {
  1499.       pdf_release_obj (named_references[i].object);
  1500.       named_references[i].object = NULL;
  1501.     }
  1502.     if (named_references[i].res_name != NULL) {
  1503.       RELEASE (named_references[i].res_name);
  1504.       named_references[i].res_name = NULL;
  1505.     }
  1506.     RELEASE (named_references[i].name);
  1507.   }
  1508.   if (number_named_references > 0)
  1509.     RELEASE (named_references);
  1510. }
  1511.  
  1512. int pdf_parse_special(char *buffer, UNSIGNED_QUAD size, double
  1513.                x_user, double y_user)
  1514. {
  1515.   int pdfmark, result=0;
  1516.   char *start = buffer, *end;
  1517.   end = buffer + size;
  1518.  
  1519. #ifdef MEM_DEBUG
  1520. MEM_START
  1521. #endif
  1522.  
  1523.   if (is_pdf_special(&start, end)) {
  1524.     result = 1; /* This means it really was a pdf special.  It doesn't
  1525.            mean it succeeded */
  1526.     /* Must have a pdf special */
  1527.     pdfmark = parse_pdfmark(&start, end);
  1528.     switch (pdfmark) {
  1529.     case ANN:
  1530.       do_ann(&start, end);
  1531.       break;
  1532.     case BANN:
  1533.       do_bann(&start, end);
  1534.       break;
  1535.     case LINK_ANNOT:
  1536.       dev_link_annot(1);
  1537.       break;
  1538.     case NOLINK_ANNOT:
  1539.       dev_link_annot(0);
  1540.       break;
  1541.     case EANN:
  1542.       do_eann(&start, end);
  1543.       break;
  1544.     case OUTLINE:
  1545.       do_outline(&start, end);
  1546.       break;
  1547.     case ARTICLE:
  1548.       do_article(&start, end);
  1549.       break;
  1550.     case BEAD:
  1551.       do_bead(&start, end);
  1552.       break;
  1553.     case DEST:
  1554.       do_dest(&start, end);
  1555.       break;
  1556.     case DOCINFO:
  1557.       do_docinfo(&start, end);
  1558.       break;
  1559.     case DOCVIEW:
  1560.       do_docview(&start, end);
  1561.       break;
  1562.     case OBJ:
  1563.       do_obj(&start, end);
  1564.       break;
  1565.     case CONTENT:
  1566.       do_content(&start, end, x_user, y_user);
  1567.       break;
  1568.     case PUT:
  1569.       do_put(&start, end);
  1570.       break;
  1571.     case CLOSE:
  1572.       do_close(&start, end);
  1573.       break;
  1574.     case BOP:
  1575.       do_bop(&start, end);
  1576.       break;
  1577.     case EOP:
  1578.       do_eop(&start, end);
  1579.       break;
  1580.     case EPDF:
  1581.       do_image(&start, end, x_user, y_user);
  1582.       break;
  1583.     case IMAGE:
  1584.       do_image(&start, end, x_user, y_user);
  1585.       break;
  1586.     case BGCOLOR:
  1587.       if (!ignore_colors)
  1588.     do_bgcolor (&start, end);
  1589.       break;
  1590.     case SCOLOR:
  1591.       if (!ignore_colors)
  1592.     do_scolor (&start, end);
  1593.       break;
  1594.     case BCOLOR:
  1595.       if (!ignore_colors)
  1596.     do_bcolor (&start, end);
  1597.       break;
  1598.     case ECOLOR:
  1599.       if (!ignore_colors)
  1600.     do_ecolor ();
  1601.       break;
  1602.     case BGRAY:
  1603.       do_bgray (&start, end);
  1604.       break;
  1605.     case EGRAY:
  1606.       do_egray ();
  1607.       break;
  1608.     case BXFORM:
  1609.       do_bxform (&start, end, x_user, y_user);
  1610.       break;
  1611.     case EXFORM:
  1612.       do_exform ();
  1613.       break;
  1614.     case PAGE_SIZE:
  1615.       do_pagesize(&start, end);
  1616.       break;
  1617.     case BXOBJ:
  1618.       do_bxobj (&start, end, x_user, y_user);
  1619.       break;
  1620.     case EXOBJ:
  1621.       do_exobj ();
  1622.       break;
  1623.     case UXOBJ:
  1624.       do_uxobj (&start, end, x_user, y_user);
  1625.       break;
  1626.     default:
  1627.       dump (start, end);
  1628.       fprintf (stderr, "Invalid pdf special ignored\n");
  1629.       break;
  1630.     }
  1631.     skip_white (&start, end);
  1632.     if (start < end) {
  1633.       fprintf (stderr, "\nUnparsed material at end of special ignored...");
  1634.       dump (start, end);
  1635.     }
  1636.   } else {
  1637.     result = 0;
  1638.   }
  1639. #ifdef MEM_DEBUG
  1640. MEM_END
  1641. #endif
  1642.   return result;
  1643. }
  1644.  
  1645. /* Compute a transformation matrix
  1646.    transformations are applied in the following
  1647.    order: scaling, rotate, displacement. */
  1648. void add_xform_matrix (double xoff, double yoff,
  1649.                double xscale, double yscale,
  1650.                double rotate) 
  1651. {
  1652.   double c, s;
  1653.   c = ROUND(cos(rotate),1e-5);
  1654.   s = ROUND(sin(rotate),1e-5);
  1655.   sprintf (work_buffer, " %g %g %g %g %.2f %.2f cm",
  1656.        c*xscale, s*xscale, -s*yscale, c*yscale, xoff, yoff);
  1657.   pdf_doc_add_to_page (work_buffer, strlen(work_buffer));
  1658. }
  1659.  
  1660.  
  1661. pdf_obj *jpeg_start_image(FILE *file)
  1662. {
  1663.   pdf_obj *xobject, *xobj_dict;
  1664.   struct jpeg *jpeg;
  1665.   jpeg = jpeg_open (file);
  1666.   xobject = pdf_new_stream(0);
  1667.   xobj_dict = pdf_stream_dict (xobject);
  1668.   pdf_add_dict (xobj_dict, pdf_new_name ("Width"),
  1669.         pdf_new_number (jpeg -> width));
  1670.   pdf_add_dict (xobj_dict, pdf_new_name ("Height"),
  1671.         pdf_new_number (jpeg -> height));
  1672.   pdf_add_dict (xobj_dict, pdf_new_name ("BitsPerComponent"),
  1673.         pdf_new_number (jpeg -> bits_per_color));
  1674.   if (jpeg->colors == 1)
  1675.     pdf_add_dict (xobj_dict, pdf_new_name ("ColorSpace"),
  1676.           pdf_new_name ("DeviceGray"));
  1677.   if (jpeg->colors > 1)
  1678.     pdf_add_dict (xobj_dict, pdf_new_name ("ColorSpace"),
  1679.           pdf_new_name ("DeviceRGB"));
  1680.   pdf_add_dict (xobj_dict, pdf_new_name ("Filter"),
  1681.         pdf_new_name ("DCTDecode"));
  1682.   {
  1683.     int length;
  1684.     rewind (jpeg -> file);
  1685.     while ((length = fread (work_buffer, sizeof (char),
  1686.                 WORK_BUFFER_SIZE, jpeg -> file)) > 0) {
  1687.       pdf_add_stream (xobject, work_buffer, length);
  1688.     }
  1689.   }
  1690.   jpeg_close (jpeg);
  1691.   return (xobject);
  1692. }
  1693.  
  1694. void pdf_scale_image (struct xform_info *p)
  1695. {
  1696.   double xscale = 1.0, yscale = 1.0, nat_width, nat_height;
  1697.   if (p->user_bbox) {  /* Did user override natural bounding box */
  1698.     nat_width  = p->u_urx - p->u_llx;
  1699.     nat_height = p->u_ury - p->u_lly;
  1700.   } else {            /* If not, use media width and height */
  1701.     nat_width  = p->c_urx - p->c_llx;
  1702.     nat_height = p->c_ury - p->c_lly;
  1703.     p->u_llx = 0.0;    /* Initialize u_llx and u_lly because they
  1704.     p->u_lly = 0.0;       are used to set the origin within the crop
  1705.               area */
  1706.   }
  1707.   if (p->clip && p->user_bbox) {  /* Clip to user specified bbox? */
  1708.     p->c_urx = p->u_urx;
  1709.     p->c_ury = p->u_ury;
  1710.     p->c_llx = p->u_llx;
  1711.     p->c_lly = p->u_lly;
  1712.   }
  1713.   if (p->scale != 0) {
  1714.     xscale = p->scale;
  1715.     yscale = p->scale;
  1716.   }
  1717.   if (p->xscale != 0) {
  1718.     xscale = p->xscale;
  1719.   }
  1720.   if (p->yscale != 0) {
  1721.     yscale = p->yscale;
  1722.   }
  1723.   if (p->width != 0.0 && nat_width != 0.0) {
  1724.     xscale = p->width/nat_width;
  1725.     if (p->height == 0.0)
  1726.       yscale = xscale;
  1727.   }
  1728.   if (p->height != 0.0 && nat_height != 0.0) {
  1729.     yscale = p->height/nat_height;
  1730.     if (p->width == 0.0)
  1731.       xscale = yscale;
  1732.   }
  1733.   /* We overwrite p->xscale and p->yscale to pass values back to
  1734.      caller to user */
  1735.   p->xscale = xscale;
  1736.   p->yscale = yscale;
  1737.   return;
  1738. }
  1739.  
  1740. static void finish_image (pdf_obj *image_res, struct xform_info *p,
  1741.               char *res_name)
  1742. {
  1743.   pdf_obj *image_dict;
  1744.   image_dict = pdf_stream_dict (image_res);
  1745.   pdf_add_dict (image_dict, pdf_new_name ("Name"),
  1746.         pdf_new_name (res_name));
  1747.   pdf_add_dict (image_dict, pdf_new_name ("Type"),
  1748.         pdf_new_name ("XObject"));
  1749.   pdf_add_dict (image_dict, pdf_new_name ("Subtype"),
  1750.         pdf_new_name ("Image"));
  1751.   { /* Compute new xscale and yscale based on user specified values
  1752.        and image dimensions (recall that PDF changes dimensions of all
  1753.        images to 1x1 :-( */
  1754.     int width, height;
  1755.     width = pdf_number_value(pdf_lookup_dict (image_dict, "Width"));
  1756.     height = pdf_number_value(pdf_lookup_dict (image_dict, "Height"));
  1757.     /* Following routine sets xscale and yscale to a fraction of
  1758.        their natural values */
  1759.     p->c_llx = 0;
  1760.     p->c_lly = 0;
  1761.     p->c_urx = width*(72.0/100.0);
  1762.     p->c_ury = height*(72.0/100.0);
  1763.     if (p->user_bbox) {
  1764.       fprintf (stderr,
  1765.            "\nWarning:  Ignoring user specified bounding box for raster image.\n");
  1766.       p->user_bbox = 0;
  1767.     }
  1768.     pdf_scale_image (p);
  1769.     /* Since bitmapped images are always 1x1 in PDF, we must rescale
  1770.        again */
  1771.     p->xscale *= width*(72.0/100.0);
  1772.     p->yscale *= height*(72.0/100.0);
  1773.   }
  1774.   return;
  1775. }
  1776.  
  1777. static void do_bxobj (char **start, char *end, double x_user, double y_user)
  1778. {
  1779.   char *objname = NULL;
  1780.   static unsigned long num_forms = 0;
  1781.   pdf_obj *xobject = NULL;
  1782.   struct xform_info *p = NULL;
  1783.   int errors = 0;
  1784.   skip_white(start, end);
  1785.   /* If there's an object name, check dimensions */
  1786.   if ((objname = parse_opt_ident(start, end)) != NULL) {
  1787.     p = new_xform_info ();
  1788.     skip_white(start, end);
  1789.     if (!parse_dimension(start, end, p)) {
  1790.       fprintf (stderr, "\nFailed to find a valid dimension.\n");
  1791.       errors = 1;
  1792.     }
  1793.     if (p->scale != 0.0 || p->xscale != 0.0 || p->yscale != 0.0) {
  1794.       fprintf (stderr, "\nScale information is meaningless for form xobjects\n");
  1795.       errors = 1;
  1796.     }
  1797.     if (p->width == 0.0 || p->depth+p->height == 0.0) {
  1798.       fprintf (stderr, "\nSpecial: bxobj: Bounding box has a zero dimension\n");
  1799.       fprintf (stderr, "width:%g, height:%g, depth:%g\n", p->width,
  1800.            p->height, p->depth);
  1801.       errors = 1;
  1802.     }
  1803.     /* If there's an object name and valid dimension, add it to the
  1804.        tables */
  1805.     if (!errors) {
  1806.       char *res_name;
  1807.       sprintf (work_buffer, "Fm%ld", ++num_forms);
  1808.       res_name = NEW (strlen(work_buffer)+1, char);
  1809.       strcpy (res_name, work_buffer);
  1810.       xobject = begin_form_xobj (x_user, y_user,
  1811.                  x_user, y_user-p->depth,
  1812.                  x_user+p->width, y_user+p->height,
  1813.                  res_name);
  1814.       add_reference (objname, xobject, res_name);
  1815.       RELEASE (res_name);
  1816.     /* Next line has Same explanation as for do_ann. */
  1817.       release_reference (objname);
  1818.     }
  1819.     release_xform_info (p);
  1820.     RELEASE (objname);
  1821.   }
  1822.   else {
  1823.     fprintf (stderr, "\nSpecial: beginxobj:  A form XObject must be named\n");
  1824.   }
  1825.   return;
  1826. }
  1827.  
  1828.  
  1829. static void do_exobj (void)
  1830. {
  1831.   end_form_xobj();
  1832. }
  1833.  
  1834. static void do_uxobj (char **start, char *end, double x_user, double y_user)
  1835. {
  1836.   char *objname, *res_name = NULL;
  1837.   pdf_obj *xobj_res = NULL;
  1838.   skip_white (start, end);
  1839.   if (((objname = parse_opt_ident(start, end)) != NULL) &&
  1840.       ((res_name = lookup_ref_res_name (objname)) != NULL) &&
  1841.       ((xobj_res = lookup_reference (objname)) != NULL)) {
  1842.     sprintf (work_buffer, " q 1 0 0 1 %.2f %.2f cm /%s Do Q", x_user, y_user, res_name);
  1843.     pdf_doc_add_to_page (work_buffer, strlen(work_buffer));
  1844.     pdf_doc_add_to_page_xobjects (res_name, xobj_res);
  1845.   }
  1846.   if (objname != NULL && (res_name == NULL || xobj_res == NULL)) {
  1847.       fprintf (stderr, "\nSpecial: usexobj:  Specified XObject doesn't exist: %s\n", 
  1848.            objname);
  1849.   }
  1850.   if (objname != NULL)
  1851.     RELEASE (objname);
  1852.   return;
  1853. }
  1854.  
  1855.